<template>
    <el-container style="height: 100%">
        <el-aside width="200px" style="height: 100%;">
            <!-- Aside -->
            <div style="height: 20%;" class="aside-header">
                <!-- 新建，清空，退出对话框。 -->
                <div class="center-item" @click="createTopicDialogFormVisible = true">新建话题</div>
                <div class="center-item" @click="deleteUserTopicListConfirm">清空话题</div>
            </div>

            <el-scrollbar height="525px">
                <el-table ref="topicTableRef" :data="tableData" :show-header="false" highlight-current-row
                    @current-change="handleCurrentChange">
                    <el-table-column property="title" width="150px" :show-overflow-tooltip="true" style="max-width: 20%" />
                    <el-table-column width="50px">
                        <template #default="{ row }">
                            <!-- 阻止冒泡，否则会误触发handleCurrentChange -->
                            <el-icon>
                                <Delete @click.stop="deleteTopicConfirm(row.id)" />
                            </el-icon>
                        </template>
                    </el-table-column>
                </el-table>
            </el-scrollbar>
            <!-- todo -->
            <div style="height: 20%" class="aside-footer">
                <div @click="toUserCenter">个人中心</div>
                <div @click="logout">退出登录</div>
            </div>
        </el-aside>

        <el-container style="background-color:azure ;">
            <el-header style="height: 70%">
                <el-scrollbar ref="scrollbarRef" height="460px">
                    <div style="height: 40px;"></div>
                    <template v-if="qaRecords.length >= 1">
                        <template v-for="(item, index) in qaRecords">
                            <template v-if="index != 0 && item.qFlag == true">
                                <el-row>
                                    <el-col :span="3"></el-col>
                                    <el-col :span="1">

                                        <el-avatar shape="square" :size="20"
                                            src="https://cube.elemecdn.com/9/c2/f0ee8a3c7c9638a54940382568c9dpng.png" />
                                    </el-col>
                                    <el-col :span="20">
                                        <div style="max-width: 80%; ">{{ item.content }}</div>

                                    </el-col>
                                </el-row>

                            </template>
                            <template v-else-if="index != 0 && item.qFlag == false">
                                <el-row>
                                    <el-col :span="3"></el-col>
                                    <el-col :span="1">
                                        <img width="20px" height="20px" style="margin: 20px 0"
                                            src="https://nlp-eb.cdn.bcebos.com/static/eb/asset/robin.e9dc83e5.png">
                                    </el-col>
                                    <el-col :span="20">
                                        <el-card style="margin: 20px 0; width: 80%; border-radius: 12px;"
                                            @click="answerClickHandler">
                                            <div v-html="formatMd(item.content)"></div>
                                        </el-card>
                                    </el-col>
                                </el-row>


                                <el-row>
                                    <el-col :span="4"></el-col>
                                    <el-col :span="20">
                                        <div v-if="answering && index == (qaRecords.length - 1)"
                                            style="color:blue; font-size: 12px;" @click="closeSSE">
                                            停止生成
                                        </div>
                                    </el-col>
                                </el-row>

                            </template>

                        </template>
                    </template>
                    <template v-else>
                        <p>无记录</p>
                    </template>
                </el-scrollbar>

                <!-- question and answer -->
            </el-header>
            <!-- main这个输入框可以加个阴影边框 -->

            <el-main style="height: 30%">
                <el-row>
                    <el-col :span="4"></el-col>
                    <el-col :span="20">
                        <el-form ref="questionRuleFormRef" :rules="questionRules" :model="questionForm">
                            <el-form-item label="" prop="question">
                                <!-- 去除两边空白 -->
                                <el-input v-model.trim="questionForm.question" autocomplete="off" placeholder="请输入要提问的内容"
                                    maxlength="500" show-word-limit type="textarea" resize="none" :rows="4"
                                    style="width: 80%;" @keydown.enter="submitQuestionForm(questionRuleFormRef)" />
                            </el-form-item>
                        </el-form>
                        <el-button type="primary" round @click="submitQuestionForm(questionRuleFormRef)">
                            发送
                        </el-button>
                    </el-col>
                </el-row>

            </el-main>
        </el-container>
    </el-container>


    <!-- 新增话题对话框 -->
    <el-dialog @close="cleanFormInput" v-model="createTopicDialogFormVisible" title="新增话题" width="400">
        <el-form ref="createTopicRuleFormRef" :rules="createTopicRules" :model="createTopicForm">
            <el-form-item label="话题名称" prop="topicTitle">
                <!-- 去除两边空白 -->
                <el-input v-model.trim="createTopicForm.topicTitle" autocomplete="off" placeholder="请输入话题名称" maxlength="30"
                    show-word-limit type="textarea" resize="none" />
            </el-form-item>
        </el-form>
        <template #footer>
            <div class="dialog-footer">
                <el-button @click="createTopicDialogFormVisible = false">
                    取消
                </el-button>
                <el-button type="primary" @click="submitCreateTopicForm(createTopicRuleFormRef)">
                    确认
                </el-button>
            </div>
        </template>
    </el-dialog>
</template>



<script lang="ts" setup>
import { ref, reactive, nextTick, onMounted } from "vue";
import MarkdownIt from 'markdown-it';
import hljs from 'highlight.js';
import 'highlight.js/styles/default.css';
// import 'highlight.js/styles/github.css';
import { Delete } from "@element-plus/icons-vue";
import { useTokenStore } from "@/stores/user";
import { useRouter } from "vue-router";
import {
    ElMessageBox,
    ElTable,
    FormInstance,
    FormRules,
    ElScrollbar,
    ElNotification
} from "element-plus";

import {
    createTopic,
    getTopicList,
    deleteTopic,
    deleteUserTopicList,
} from "@/api/topic";
import { getQaListInTopic } from "@/api/qa";

onMounted(() => {
    //挂载后调用updateTOpicList。
    updateTopicList();
});


const md = new MarkdownIt({
    highlight: function (str, lang) {
        if (lang && hljs.getLanguage(lang)) {
            return highlightBlock(hljs.highlight(lang, str).value, lang);
        }
        return '';
    }
});

const highlightBlock = (str, lang) => {
    return `<pre class="pre-code-box"><div class="pre-code-header"><span class="code-block-header__lang">${lang}</span><span class="code-block-header__copy">复制代码</span></div><div class="pre-code"><code class="hljs code-block-body ${lang}">${str}</code></div></pre>`
}
const formatMd = str => md.render(str);


const answerClickHandler = async ($event) => {
    if ($event.target.className == 'code-block-header__copy') {
        await navigator.clipboard.writeText($event.target.parentElement.parentElement.querySelector('code').textContent);
        ElNotification({
            title: '成功',
            message: '复制成功',
            type: 'success',
        });
    }
}


const tokenStore = useTokenStore();
const router = useRouter();
const store = useTokenStore();

const scrollbarRef = ref<InstanceType<typeof ElScrollbar>>();
//刷新话题列表
const updateTopicList = async () => {
    console.log("-------------updateTopicList----------");

    try {
        const result = await getTopicList();
        console.log("result" + result);
        console.log("resultType" + Object.prototype.toString.call(result));
        console.log("resultDataType" + Object.prototype.toString.call(result.data));
        console.log("call getTopicList finish with data:" + result.data);

        if (result.data.length !== 0) {
            console.log("topicList[0].id" + result.data[0].id);
            tableData.splice(0, tableData.length, ...result.data);
        } else {
            tableData.splice(0, tableData.length);
        }
        //清空qa记录
        qaRecords.splice(1,qaRecords.length);


    } catch (error) {
        console.error("Error fetching topic list:", error);
    }
    console.log("------end----updateTopicList----end---");
};




//删除单个话题
const deleteTopicConfirm = async (topicId) => {
    try {
        await ElMessageBox.confirm("确定要删除这个话题吗？", "删除话题", {
            confirmButtonText: "删除",
            cancelButtonText: "取消",
            type: "warning",
        })
        console.log("-------------------deleteTopicConfirm-----------------");

        console.log("delete" + topicId);

        await deleteTopic(topicId);
        console.log("delete finish");

        await ElMessageBox.alert("删除成功", "提示", {
            confirmButtonText: "确定",
        })
        console.log("删除成功");

        await updateTopicList();
        console.log("获取新数据成功");

        console.log("end----------------deleteTopicConfirm--------------end");
    } catch (error) {
        if (error == 'cancel') {
            console.log("取消删除");
        }
    }
};



//清空话题
const deleteUserTopicListConfirm = async () => {
    try {
        // 等待用户确认  
        await ElMessageBox.confirm("确定要删除全部话题吗", "删除话题", {
            confirmButtonText: "确认删除",
            cancelButtonText: "取消",
            type: "warning",
        });

        console.log("-------------------deleteUserTopicList-----------------");

        // 等待删除操作完成  
        await deleteUserTopicList(store.id);

        // 删除成功后显示提示  
        await ElMessageBox.alert("删除成功", "提示", {
            confirmButtonText: "确定",
        });

        console.log("全部删除完成");
        await updateTopicList();
        console.log("end----------------deleteUserTopicList--------------end");
    } catch (error) {
        // 处理可能出现的错误  
        // console.error("errorType:", Object.prototype.toString.call(error));  
        if (error == 'cancel') {
            console.log("取消删除");
        }
    }
};


//新增话题对话框
const createTopicRuleFormRef = ref<FormInstance>();
const createTopicDialogFormVisible = ref(false);
const createTopicForm = reactive({
    topicTitle: "",
});

// let topicList = ref([]);

const validateTitle = (rule: any, value: any, callback: any) => {
    if (value === "") {
        callback(new Error("请输入话题名称"));
    } else {
        callback();
    }
};

const createTopicRules = reactive<FormRules<typeof createTopicForm>>({
    topicTitle: [{ validator: validateTitle, trigger: "blur" }],
});

const submitCreateTopicForm = async (formEl: FormInstance | undefined) => {
    if (!formEl) return;
    console.log("---------------------submitCreateTopicForm------------------------");

    formEl.validate(async (valid) => {
        console.log('valid:' + valid);
        if (valid) {
            console.log("title" + createTopicForm.topicTitle);

            createTopicDialogFormVisible.value = false;

            await createTopic(createTopicForm.topicTitle);
            await updateTopicList();
            console.log("create ok");
        } else {
            console.log("error submit!");
        }
        console.log("end------------------submitCreateTopicForm---------------------end");
    })

};



const closeSSE = () => {
    if (evtSource != null) {
        evtSource.close();
        console.log("close sse");

        //没拿到任何数据，answer内容修改成停止生成
        console.log("closeSSE停止生成:" + firstCallOnMessage.value);
        if (firstCallOnMessage.value == true) {
            qaRecords[qaRecords.length - 1]["content"] = '已停止生成';
        }

        firstCallOnMessage.value = true;
        answering.value = false;
        evtSource = null;
        console.log('evtSource:' + evtSource);
    }
}

const submitQuestionForm = async (formEl: FormInstance | undefined) => {
    console.log("clickSubmitQuestion");
    if (!formEl) {
        return;
    }

    formEl.validate(async (valid) => {
        console.log('valid:' + valid);
        if (valid) {

            if (answering.value == true) {
                console.log("alert");

                ElNotification({
                    title: '警告',
                    message: '请在机器人回答完成后再做提问',
                    type: 'warning',
                })

                return;
            }

            if (currentRow.value == undefined) {
                try {
                    await createTopic(questionForm.question.substring(0, 30));
                    console.log("created topic");
                    await updateTopicList();
                    console.log("updateTopicList finish");
                    if (tableData.length > 0) {
                        // topicTableRef.value.setCurrentRow(tableData[0]);
                        await handleCurrentChange(tableData[0]);
                        console.log("setCurRowId:", tableData[0].id);
                        console.log("Current Row:", JSON.stringify(tableData[0]));
                    }
                } catch (error) {
                    console.log("currentRow set error:" + error);
                }

            }




            console.log("----qaRecords start push----");
            console.log(qaRecords.length);
            //渲染提问和回答
            qaRecords.push({
                qFlag: true,
                content: questionForm.question,
            });
            qaRecords.push({
                qFlag: false,
                content: "思考中...",
            });
            console.log(qaRecords.length);
            answering.value = true;

            evtSource = new EventSource(
                "http://localhost:9090/qa/chat?Authorization=" +
                tokenStore.Authorization +
                "&topicId=" +
                currentRow.value.id +
                "&message=" +
                questionForm.question
            );
            console.log("try connect");

            // 监听连接打开
            evtSource.onopen = function () {
                console.log("Connection to server opened.");


                //清空输入框
                questionForm.question = "";
            };

            // 监听服务器发送的消息
            // todo在做的时候应该始终让滑动条在最下面
            evtSource.onmessage = function (e) {
                console.log("message");
                console.log("answer:" + answering.value);
                const message = e.data;

                //第一次，初始化内容。后续则是追加。
                if (firstCallOnMessage.value == true) {
                    qaRecords[qaRecords.length - 1]["content"] = message;
                    firstCallOnMessage.value = false;
                    console.log("firstCallOnMessage.value=" + firstCallOnMessage.value);
                } else {
                    qaRecords[qaRecords.length - 1]["content"] += message;
                }
                //ai回答过程中，若正在追加的那一行显示在屏幕里要将滚动条持续滚到最底部。
                if (
                    scrollbarRef.value.wrapRef.scrollHeight -
                    scrollbarRef.value.wrapRef.scrollTop <
                    500
                ) {
                    console.log("scroll");
                    scrollbarRef.value.wrapRef.scrollTop = scrollbarRef.value.wrapRef.scrollHeight;
                } else {
                    console.log("not scroll");
                    console.log("scrollTop:" + scrollbarRef.value.wrapRef.scrollTop);
                    console.log("scrollHeight:" + scrollbarRef.value.wrapRef.scrollHeight);
                }
            };

            //处理token过期事件。
            evtSource.addEventListener("tokenInvalid", async function (e) {
                console.log(e);
                console.log("error token");
                console.log(e.data);

                try {
                    await ElMessageBox.confirm("登录凭证失效，请重新登陆", "Confirm logout", {
                        confirmButtonText: "重新登陆",
                        cancelButtonText: "取消",
                        type: "error",
                    })
                    router.push('/login');
                } catch (error) {
                    console.log("凭证失效，但什么都不做");
                }

            });


            //token不足。
            evtSource.addEventListener("insufficientToken", async function (e) {
                console.log(e);
                console.log("insufficientToken");
                console.log(e.data);

                qaRecords[qaRecords.length - 1]["content"] = '账户余额不足';

                firstCallOnMessage.value = true;
                answering.value = false;
                evtSource.close();
                evtSource = null;
                console.log('evtSource:' + evtSource);

            });


            evtSource.addEventListener("finish", async function (e) {
                console.log(e);
                console.log("finish sse");
                console.log(e.data);

                evtSource.close();
                console.log("close sse");
                firstCallOnMessage.value = true;
                answering.value = false;
                evtSource = null;
                console.log('evtSource:' + evtSource);
            });

            // 监听连接错误
            evtSource.onerror = function () {
                console.log("error");

                qaRecords[qaRecords.length - 1]["content"] = '网络异常';

                evtSource.close();
                evtSource = null;
                console.log("evtSource closed");

                firstCallOnMessage.value = true;
                answering.value = false;
            };
        }
        else {
            console.log("error submit!");
            return;

        }
    });
};

const toUserCenter = () => {
    router.push("/userCenter");
};

//问答记录
const qaRecords = reactive([
    {
        qFlag: true,
        content: "",
    },
]);
const firstCallOnMessage = ref(true);
const answering = ref(false);

//提问表单
const questionRuleFormRef = ref<FormInstance>();
const questionForm = reactive({
    question: "",
});


const validateQuestion = (rule: any, value: any, callback: any) => {
    if (value === "") {
        callback(new Error("请输入问题"));
    } else {
        callback();
    }
};

const questionRules = reactive<FormRules<typeof questionForm>>({
    question: [{ validator: validateQuestion, trigger: "blur" }],
});

let evtSource = null;

//关闭对话框时清理输入内容
const cleanFormInput = () => {
    createTopicForm.topicTitle = "";
};


//话题列表数据
interface Topic {
    id: number;
    title: string;
}

const tableData: Topic[] = reactive([]);
const currentRow = ref();
const topicTableRef = ref<InstanceType<typeof ElTable>>();



//切换话题
const handleCurrentChange = async (val: Topic | undefined) => {

    console.log("--------------handleCurrentChange-----------------");
    if (evtSource != null) {
        console.log("关闭SSE连接");
        evtSource.close();

        firstCallOnMessage.value = true;
        answering.value = false;
    } else {
        console.log("evtSource为null");
    }
    currentRow.value = val;
    console.log("currentRow.value:" + JSON.stringify(currentRow.value));
    console.log("val:" + val);
    if (currentRow.value) {
        console.log(currentRow.value.id);
        console.log("val.id:" + val.id);
    }


    try {
        const result = await getQaListInTopic(val.id);
        console.log("getQARecords success");


        console.log(result);
        console.log(result.data);

        //直接赋值会影破坏响应性，要用数组方法来做赋值。这里就用splice了
        //重置qa记录
        if (result.data.length !== 0)
            qaRecords.splice(1, qaRecords.length, ...result.data);
        else
            qaRecords.splice(1, qaRecords.length);
        console.log(qaRecords);
        console.log(qaRecords.length);
        //获取了qa记录后在渲染完毕后要滑动到最末尾。
        //dom更新数据后调用。
        nextTick(() => {
            console.log("next tick，滑动滚动条到末尾");
            if (scrollbarRef.value) {
                scrollbarRef.value.wrapRef.scrollTop =
                    scrollbarRef.value.wrapRef.scrollHeight;
            }
        });
    } catch (error) {
        console.log("handleCurrentChange error:" + error);
    }

    console.log("end-----------handleCurrentChange--------------end");
};



//退出登录
const logout = async () => {
    try {
        await ElMessageBox.confirm("确定要退出吗", "退出登录", {
            confirmButtonText: "确认",
            cancelButtonText: "取消",
            type: "warning",
        });

        console.log("----------------logout------------");
        store.logout();
        router.push("/login");

        console.log("endBefore----------logout---------endBefore");

        console.log("endAfter----------logout---------endAfter");

    } catch (error) {
        if (error == 'cancel') {
            console.log("取消删除");
        }
    }
};
</script>



<style>
.aside-header,
.aside-footer {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 0;
    background-color: #f5f5f5;
    border-bottom: 2px solid #e4e4e4;
}

.aside-header div,
.aside-footer div {
    cursor: pointer;
    padding: 10px 65px;
    margin: 5px 0;
    border-radius: 4px;
    transition: background-color 0.3s;
}

.aside-header div:hover,
.aside-footer div:hover {
    background-color: #eee;
}


.center-item {
    margin: 5px 0;
    /* 上下边距 */
}


.scrollbar-content {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    height: 100%;
}






.grid-content {
    border-radius: 4px;
    min-height: 36px;
}

.scrollbar-demo-item {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 50px;
    margin: 10px;
    text-align: center;
    border-radius: 4px;
    background: var(--el-color-primary-light-9);
    color: var(--el-color-primary);
}



.pre-code-header {
    align-items: center;
    background: #30313d;
    border-radius: 7px 7px 0 0;
    display: flex;
    height: 37px;
}


.code-block-header__lang {
    color: #fff;
    flex: 1 0 auto;
    font-family: PingFang SC !important;
    font-size: 18px;
    font-weight: 600;
    letter-spacing: 0;
    line-height: 26px;
    padding-left: 14px;
    text-align: justify;
}

.code-block-header__copy {
    align-items: center;
    color: hsla(0, 0%, 100%, .7);
    display: flex;
    font-family: PingFangSC-Regular;
    font-size: 12px;
    font-weight: 400;
    letter-spacing: 0;
    line-height: 14px;
    text-align: justify;
    user-select: none;
    margin-right: 10px;
}
</style>